﻿#region using...
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
#endregion

namespace Infusion.Silverlight.Controls.Ribbon
{
    #region : RibbonTab :
    #region Template Parts...
    [TemplatePart(Name = RibbonTab.RibbonTabLayoutRoot, Type = typeof(Canvas))]
    [TemplatePart(Name = RibbonTab.TxtTitle, Type = typeof(TextBlock))]
    [TemplatePart(Name = RibbonTab.GridText, Type = typeof(Grid))]
    [TemplatePart(Name = RibbonTab.PathCanvasClipFigure, Type = typeof(PathFigure))]
    [TemplatePart(Name = RibbonTab.PathOuterBorder, Type = typeof(Path))]
    [TemplatePart(Name = RibbonTab.PathOuterBorderFigure, Type = typeof(PathFigure))]
    [TemplatePart(Name = RibbonTab.PathInnerBorder, Type = typeof(Path))]
    [TemplatePart(Name = RibbonTab.PathInnerBorderFigure, Type = typeof(PathFigure))]
    [TemplatePart(Name = RibbonTab.StoryboardTabHighlight, Type = typeof(Storyboard))]
    [TemplatePart(Name = RibbonTab.StoryboardTabHighlightSelected, Type = typeof(Storyboard))]
    #endregion
    [ContentProperty("Groups")]
    public class RibbonTab : Control
    {
        #region Constants...
        private const double tabPadding = 28;
        #endregion

        #region TemplatePart Names...
        public const string RibbonTabLayoutRoot = "RibbonTabLayoutRoot";
        public const string TxtTitle = "TxtTitle";
        public const string GridText = "GridText";
        public const string PathCanvasClipFigure = "PathCanvasClipFigure";
        public const string PathOuterBorder = "PathOuterBorder";
        public const string PathOuterBorderFigure = "PathOuterBorderFigure";
        public const string PathInnerBorder = "PathInnerBorder";
        public const string PathInnerBorderFigure = "PathInnerBorderFigure";
        public const string StoryboardTabHighlight = "StoryboardTabHighlight";
        public const string StoryboardTabHighlightSelected = "StoryboardTabHighlightSelected";
        #endregion

        #region TemplatePart Variables...
        private Canvas ribbonTabLayoutRoot;
        private TextBlock txtTitle;
        private Grid gridText;
        private PathFigure pathCanvasClipFigure;
        private Path pathOuterBorder;
        private PathFigure pathOuterBorderFigure;
        private Path pathInnerBorder;
        private PathFigure pathInnerBorderFigure;
        private Storyboard storyboardTabHighlight;
        private Storyboard storyboardTabHighlightSelected;
        #endregion

        #region Class Variables...
        private Ribbon parentRibbon;
        private bool textLayoutUpdated = false;
        private bool mouseOver = false;
        private bool selected = false;
        private bool hasLoaded = false;
        private LinearGradientBrush tabSelectedBrush;
        private LinearGradientBrush tabHoverBrush;
        #endregion

        #region Dependency Properties...
        #region GroupsProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Ribbon.RibbonTab.Groups dependency property.
        /// </summary>
        public static readonly DependencyProperty GroupsProperty = DependencyProperty.Register(
                "Groups",
                typeof(RibbonTabGroupCollection),
                typeof(RibbonTab),
                null);
        #endregion

        #region TitleProperty
        /// <summary>
        /// Identifies the Infusion.Silverlight.Controls.Ribbon.RibbonTab.Title dependency property.
        /// </summary>
        public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
                "Title",
                typeof(string),
                typeof(RibbonTab),
                new PropertyMetadata(new PropertyChangedCallback(TitlePropertyChanged)));
        #endregion
        #endregion

        #region Dependency Property Changed Handlers...
        #region TitlePropertyChanged
        private static void TitlePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            if (args.NewValue != null)
            {
                RibbonTab tab = (RibbonTab)obj;
                tab.SetText(args.NewValue.ToString());
            }
            else
            {
                throw new ArgumentNullException("Title can not be null or an empty string.");
            }
        }
        #endregion
        #endregion

        #region Constructor(s)...
        #region RibbonTab
        public RibbonTab() : base()
        {
            DefaultStyleKey = typeof(RibbonTab);

            Groups = new RibbonTabGroupCollection();
            Groups.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Groups_CollectionChanged);

            //tabSelectedBrush...
            Dictionary<double, Color> tabSelectedBrushGradientStops = new Dictionary<double, Color>();
            tabSelectedBrushGradientStops.Add(0.0, Helper.HexToColor("#F5F6F6"));
            tabSelectedBrushGradientStops.Add(0.5, Helper.HexToColor("#EAEDF2"));
            tabSelectedBrushGradientStops.Add(1.0, Helper.HexToColor("#ECEFF4"));

            tabSelectedBrush = new LinearGradientBrush();
            tabSelectedBrush.StartPoint = new Point(0.5, 0);
            tabSelectedBrush.EndPoint = new Point(0.5, 1);
            tabSelectedBrush.GradientStops = Helper.CreateGradientStopCollection(tabSelectedBrushGradientStops);

            //tabHoverBrush...
            Dictionary<double, Color> tabHoverBrushGradientStops = new Dictionary<double, Color>();
            tabHoverBrushGradientStops.Add(0.0, Helper.HexToColor("#D5D5D6"));
            tabHoverBrushGradientStops.Add(0.5, Helper.HexToColor("#E8E5DC"));
            tabHoverBrushGradientStops.Add(1.0, Helper.HexToColor("#E7CF98"));

            tabHoverBrush = new LinearGradientBrush();
            tabHoverBrush.StartPoint = new Point(0.5, 0);
            tabHoverBrush.EndPoint = new Point(0.5, 1);
            tabHoverBrush.GradientStops = Helper.CreateGradientStopCollection(tabHoverBrushGradientStops);
        }
        #endregion
        #endregion

        #region Event Handlers...
        #region ribbonTabLayoutRoot_LayoutUpdated
        private void ribbonTabLayoutRoot_LayoutUpdated(object sender, EventArgs e)
        {
            if (!textLayoutUpdated)
            {
                SetPathFigures();
                textLayoutUpdated = true;
            }
        }
        #endregion

        #region ribbonTabLayoutRoot_MouseLeave
        private void ribbonTabLayoutRoot_MouseLeave(object sender, MouseEventArgs e)
        {
            mouseOver = false;
            BlurTab();
        }
        #endregion

        #region ribbonTabLayoutRoot_MouseEnter
        private void ribbonTabLayoutRoot_MouseEnter(object sender, MouseEventArgs e)
        {
            mouseOver = true;
            FocusTab();            
        }
        #endregion

        #region ribbonTabLayoutRoot_MouseLeftButtonDown
        private void ribbonTabLayoutRoot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            parentRibbon.SelectedTabIndex = parentRibbon.Tabs.IndexOf(this);
        }
        #endregion

        #region Groups_CollectionChanged
        private void Groups_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    foreach (RibbonTabGroup group in e.NewItems)
                    {
                        group.ParentRibbonTab = this;
                    }
                    break;
                case NotifyCollectionChangedAction.Remove:
                    break;
                case NotifyCollectionChangedAction.Replace:
                    break;
                case NotifyCollectionChangedAction.Reset:
                    break;
                default:
                    break;
            }
        }
        #endregion
        #endregion

        #region Methods...
        #region SetPathFigures
        private void SetPathFigures()
        {
            ribbonTabLayoutRoot.Width = txtTitle.ActualWidth + tabPadding;
            gridText.ColumnDefinitions[0].Width = new GridLength(txtTitle.ActualWidth + tabPadding);

            pathCanvasClipFigure.StartPoint = new Point(selected ? 0 : 2.5, selected ? 23 : 22);
            pathCanvasClipFigure.Segments = GenerateBorderSegments(txtTitle.ActualWidth + tabPadding, true);

            pathOuterBorderFigure.StartPoint = new Point(selected ? 0 : 2.5, 22.5);
            pathOuterBorderFigure.Segments = GenerateBorderSegments(txtTitle.ActualWidth + tabPadding, false);

            pathInnerBorderFigure.StartPoint = new Point(selected ? 0 : 2.5, 22.5);
            pathInnerBorderFigure.Segments = GenerateBorderSegments(txtTitle.ActualWidth + tabPadding - 2, false);
        }
        #endregion

        #region BlurTab
        internal void BlurTab()
        {
            if (!ParentRibbon.HasMenuOpen)
            {
                if (selected)
                {
                    storyboardTabHighlightSelected.Begin();
                }
                else
                {
                    pathInnerBorder.Visibility = Visibility.Collapsed;
                    pathOuterBorder.Visibility = Visibility.Collapsed;

                    storyboardTabHighlight.Begin();
                }
            }
        }
        #endregion

        #region FocusTab
        internal void FocusTab()
        {
            if (!ParentRibbon.HasMenuOpen)
            {
                if (selected)
                {
                    storyboardTabHighlightSelected.Stop();

                    pathOuterBorder.Stroke = new SolidColorBrush(Helper.HexToColor("#FED15E"));
                    pathOuterBorder.StrokeThickness = 3;
                    pathOuterBorder.Opacity = 0.6;
                }
                else
                {
                    storyboardTabHighlight.Stop();

                    tabHoverBrush.GradientStops[0].Color = Helper.HexToColor("#D5D5D6");
                    tabHoverBrush.GradientStops[1].Color = Helper.HexToColor("#E8E5DC");
                    tabHoverBrush.GradientStops[2].Color = Helper.HexToColor("#E7CF98");

                    ribbonTabLayoutRoot.Background = tabHoverBrush;
                    pathInnerBorder.Visibility = Visibility.Visible;
                    pathOuterBorder.Visibility = Visibility.Visible;
                }
            }
        }
        #endregion

        #region GenerateBorderSegments
        private PathSegmentCollection GenerateBorderSegments(double width, bool extraHeight)
        {
            PathSegmentCollection segments = new PathSegmentCollection();

            if (extraHeight) segments.Add(Helper.GenerateLineSegment(0, 22.5));
            if (selected) segments.Add(Helper.GenerateArcSegment(SweepDirection.Counterclockwise, 2.5, 20, 2.5, 2.5));
            segments.Add(Helper.GenerateLineSegment(2.5, 2.5));
            segments.Add(Helper.GenerateArcSegment(SweepDirection.Clockwise, 5, 0, 2.5, 2.5));
            segments.Add(Helper.GenerateLineSegment(width - 5, 0));
            segments.Add(Helper.GenerateArcSegment(SweepDirection.Clockwise, width - 2.5, 2.5, 2.5, 2.5));
            segments.Add(Helper.GenerateLineSegment(width - 2.5, 20 + (Selected ? 0 : 2.5)));
            if (selected) segments.Add(Helper.GenerateArcSegment(SweepDirection.Counterclockwise, width, 22.5, 2.5, 2.5));
            if (extraHeight) segments.Add(Helper.GenerateLineSegment(width, 23));

            return segments;
        }
        #endregion

        #region OnApplyTemplate
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            ribbonTabLayoutRoot = (Canvas)GetTemplateChild(RibbonTabLayoutRoot);
            txtTitle = (TextBlock)GetTemplateChild(TxtTitle);
            gridText = (Grid)GetTemplateChild(GridText);
            pathCanvasClipFigure = (PathFigure)GetTemplateChild(PathCanvasClipFigure);
            pathOuterBorder = (Path)GetTemplateChild(PathOuterBorder);
            pathOuterBorderFigure = (PathFigure)GetTemplateChild(PathOuterBorderFigure);
            pathInnerBorder = (Path)GetTemplateChild(PathInnerBorder);
            pathInnerBorderFigure = (PathFigure)GetTemplateChild(PathInnerBorderFigure);
            storyboardTabHighlight = (Storyboard)GetTemplateChild(StoryboardTabHighlight);
            storyboardTabHighlightSelected = (Storyboard)GetTemplateChild(StoryboardTabHighlightSelected);

            ribbonTabLayoutRoot.LayoutUpdated += new EventHandler(ribbonTabLayoutRoot_LayoutUpdated);
            ribbonTabLayoutRoot.MouseEnter += new MouseEventHandler(ribbonTabLayoutRoot_MouseEnter);
            ribbonTabLayoutRoot.MouseLeave += new MouseEventHandler(ribbonTabLayoutRoot_MouseLeave);
            ribbonTabLayoutRoot.MouseLeftButtonDown += new MouseButtonEventHandler(ribbonTabLayoutRoot_MouseLeftButtonDown);

            txtTitle.Text = Title;

            if (selected)
            {
                ribbonTabLayoutRoot.Background = tabSelectedBrush;
                pathOuterBorder.Visibility = Visibility.Visible;
            }

            for (int groupIndex = 0; groupIndex < Groups.Count; groupIndex++)
            {
                if (parentRibbon.TabContentDictionary[this].ColumnDefinitions.Count - 1 < groupIndex)
                    parentRibbon.TabContentDictionary[this].ColumnDefinitions.Add(Helper.CreateGridColumnDefinition(0, GridUnitType.Auto));

                Groups[groupIndex].SetValue(Grid.ColumnProperty, groupIndex);
                Groups[groupIndex].SetValue(Grid.RowProperty, 0);

                parentRibbon.TabContentDictionary[this].Children.Add(Groups[groupIndex]);
            }
        }
        #endregion

        #region SetText
        private void SetText(string title)
        {
            textLayoutUpdated = false;
            if (txtTitle != null)
                txtTitle.Text = Title;
        }
        #endregion
        #endregion

        #region Properties...
        #region Groups
        public RibbonTabGroupCollection Groups
        {
            get { return (RibbonTabGroupCollection)GetValue(GroupsProperty); }
            set { SetValue(GroupsProperty, value); }
        }
        #endregion

        #region Selected
        internal bool Selected
        {
            get
            {
                return selected;
            }
            set
            {
                selected = value;
                SetPathFigures();

                if (selected)
                {
                    ribbonTabLayoutRoot.Background = tabSelectedBrush;
                    pathInnerBorder.Visibility = Visibility.Collapsed;
                    pathOuterBorder.Visibility = Visibility.Visible;
                    parentRibbon.TabContentDictionary[this].Visibility = Visibility.Visible;
                }
                else
                {
                    ribbonTabLayoutRoot.Background = new SolidColorBrush(Colors.Transparent);
                    pathInnerBorder.Visibility = Visibility.Collapsed;
                    pathOuterBorder.Visibility = Visibility.Collapsed;
                    parentRibbon.TabContentDictionary[this].Visibility = Visibility.Collapsed;
                }

                if (mouseOver)
                    FocusTab();
            }
        }
        #endregion

        #region HasLoaded
        public bool HasLoaded
        {
            get { return hasLoaded; }
            internal set { hasLoaded = value; }
        }
        #endregion

        #region ParentRibbon
        public Ribbon ParentRibbon
        {
            get { return parentRibbon; }
            set { parentRibbon = value; }
        }
        #endregion

        #region Title
        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }
        #endregion
        #endregion
    }
    #endregion

    #region : RibbonTabGroupCollection :
    public class RibbonTabGroupCollection : ObservableCollection<RibbonTabGroup>
    {
    }
    #endregion
}